package org.mozhu.simple.rpc.server.network;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

public class PlaintextTransportLayer implements TransportLayer {
    private final SelectionKey key;
    private final SocketChannel socketChannel;

    public PlaintextTransportLayer(SelectionKey key) throws IOException {
        this.key = key;
        this.socketChannel = (SocketChannel) key.channel();
    }

    /**
     * Reads a sequence of bytes from this channel into the given buffer.
     *
     * @param dst The buffer into which bytes are to be transferred
     * @return The number of bytes read, possible zero or -1 if the channel has reached end-of-stream
     * @throws IOException if some other I/O error occurs
     */
    @Override
    public int read(ByteBuffer dst) throws IOException {
        return socketChannel.read(dst);
    }

    /**
     * Reads a sequence of bytes from this channel into the given buffers.
     *
     * @param dsts - The buffers into which bytes are to be transferred.
     * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream.
     * @throws IOException if some other I/O error occurs
     */
    @Override
    public long read(ByteBuffer[] dsts) throws IOException {
        return socketChannel.read(dsts);
    }

    /**
     * Reads a sequence of bytes from this channel into a subsequence of the given buffers.
     *
     * @param dsts   - The buffers into which bytes are to be transferred
     * @param offset - The offset within the buffer array of the first buffer into which bytes are to be transferred; must be non-negative and no larger than dsts.length.
     * @param length - The maximum number of buffers to be accessed; must be non-negative and no larger than dsts.length - offset
     * @throws IOException if some other I/O error occurs
     * @returns The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream.
     */
    @Override
    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
        return socketChannel.read(dsts, offset, length);
    }

    /**
     * Writes a sequence of bytes to this channel from the given buffer.
     *
     * @param src The buffer from which bytes are to be retrieved
     * @throws IOException If some other I/O error occurs
     * @returns The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
     */
    @Override
    public int write(ByteBuffer src) throws IOException {
        return socketChannel.write(src);
    }

    /**
     * Writes a sequence of bytes to this channel from the given buffer.
     *
     * @param srcs The buffer from which bytes are to be retrieved
     * @throws IOException If some other I/O error occurs
     * @returns The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream
     */
    @Override
    public long write(ByteBuffer[] srcs) throws IOException {
        return socketChannel.write(srcs);
    }

    /**
     * Writes a sequence of bytes to this channel from the subsequence of the given buffers.
     *
     * @param srcs   The buffers from which bytes are to be retrieved
     * @param offset The offset within the buffer array of the first buffer from which bytes are to be retrieved; must be non-negative and no larger than srcs.length.
     * @param length - The maximum number of buffers to be accessed; must be non-negative and no larger than srcs.length - offset.
     * @return returns no.of bytes written , possibly zero.
     * @throws IOException If some other I/O error occurs
     */
    @Override
    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
        return socketChannel.write(srcs, offset, length);
    }

    @Override
    public boolean isOpen() {
        return socketChannel.isOpen();
    }

    /**
     * Closes this channel
     *
     * @throws IOException If I/O error occurs
     */
    @Override
    public void close() throws IOException {
        try {
            socketChannel.socket().close();
            socketChannel.close();
        } finally {
            key.attach(null);
            key.cancel();
        }
    }

    /**
     * Adds the interestOps to selectionKey.
     *
     * @param ops
     */
    @Override
    public void addInterestOps(int ops) {
        key.interestOps(key.interestOps() | ops);

    }

    /**
     * Removes the interestOps from selectionKey.
     *
     * @param ops
     */
    @Override
    public void removeInterestOps(int ops) {
        key.interestOps(key.interestOps() & ~ops);
    }
}
